package withdraw

import (
	"context"
	"strings"
	"time"

	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/model/query"
	modelWithdraw "gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/schema/withdraw"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/svc"
	re "gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/redis_utils"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/xerrors"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/rpc"
	"github.com/jinzhu/copier"
	"github.com/jinzhu/now"
	"github.com/spf13/cast"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
)

type TypeModel struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
	tx *query.Query
}

func (model *TypeModel) getDb() *gorm.DB {
	if model.svcCtx.Db != nil {
		return model.svcCtx.Db
	}
	return svc.Db
}
func NewTypeModel(ctx context.Context, svc *svc.ServiceContext) *TypeModel {
	return &TypeModel{
		ctx:    ctx,
		svcCtx: svc,
		Logger: logx.WithContext(ctx),
	}
}
func (l *TypeModel) WithdrawTypeUpdate(in *rpc.UpdateWithDrawTypeRequest) (ret *rpc.UpdateWithDrawTypeResponse, err error) {
	// todo: add your logic here and delete this line
	ret = &rpc.UpdateWithDrawTypeResponse{}
	g := query.Use(l.getDb()).WithdrawType
	h := g.Where(g.ID.Eq(in.WithDrawType.ID))
	d, err2 := h.First()
	if err2 != nil {
		return nil, err
	}
	_, err = h.UpdateSimple(g.SelectedIcon.Value(in.WithDrawType.SelectedIcon),
		g.UnselectedIcon.Value(in.WithDrawType.UnselectedIcon),
		g.Type.Value(in.WithDrawType.Type),
		g.DailyTimes.Value(in.WithDrawType.DailyTimes),
		g.CurTimes.Add(in.WithDrawType.DailyTimes-d.DailyTimes),
		g.WithdrawTime.Value(in.WithDrawType.WithdrawTime),
		g.MinAmount.Value(in.WithDrawType.MinAmount),
		g.MaxAmount.Value(in.WithDrawType.MaxAmount),
		g.FeeRate.Value(in.WithDrawType.FeeRate),
		g.Status.Value(in.WithDrawType.Status),
		g.Sort.Value(in.WithDrawType.Sort),
	)
	if err != nil {
		return nil, err
	}
	ret.Data = &rpc.WithDrawType{}
	copier.Copy(ret.Data, in.WithDrawType)
	return ret, nil
}
func (l *TypeModel) WithdrawTypeTotalUpdate(in *rpc.WithdrawTypeTotalUpdateReq) (*rpc.WithdrawTypeTotalUpdateRes, error) {
	ret := &rpc.WithdrawTypeTotalUpdateRes{}
	err := re.SetTokenRedis(l.ctx, l.svcCtx.Config.RedisConfig, rpc.RedisKey_name[int32(rpc.RedisKey_WithdrawTotal)], in.Total)
	if err != nil {
		return nil, err
	}
	return ret, nil
}
func (l *TypeModel) WithdrawTypeDel(in *rpc.WithdrawTypeDelRequest) (*rpc.WithdrawTypeDelResponse, error) {
	ret := &rpc.WithdrawTypeDelResponse{}
	g := query.Use(l.getDb()).WithdrawType
	g.Where(g.ID.Eq(in.Id)).Delete(&modelWithdraw.WithdrawType{})
	return ret, nil
}
func (l *TypeModel) WithdrawTypeList(in *rpc.GetWithDrawTypeRequest) (*rpc.GetWithDrawTypeResponse, error) {
	ret := &rpc.GetWithDrawTypeResponse{}
	if in.UserId != 0 {
		g2 := query.Use(l.getDb()).UserWallet
		d, err := g2.Where(g2.UserId.Eq(in.UserId)).First()
		if err != nil {
			return nil, xerrors.ErrNoRows
		}
		if d.ValidMark > d.ValidConsume {
			ret.Valid = d.ValidMark - d.ValidConsume
		}
	}

	g := query.Use(l.getDb()).WithdrawType
	dbModel := g.Where()
	if in.Name != 0 {
		dbModel = dbModel.Where(g.Type.Eq(in.Name))
	}
	if in.Status != rpc.WithdrawStatus_All {
		dbModel = dbModel.Where(g.Status.Eq(modelWithdraw.ProtoStatusToConst(in.Status)))
	}

	d, err := dbModel.Order(g.Sort.Asc()).Find()
	if err != nil {
		return nil, xerrors.ErrNoRows
	}
	t2 := l.WithdrawTotalGet()
	t1 := l.WithdrawTotalCurGet()
	t := t2 - t1
	for i, _ := range d {
		d2 := &rpc.WithDrawType{}
		copier.Copy(d2, d[i])
		m := NewVirtualDicModel(l.ctx, l.svcCtx)
		d2.Rate = m.GetRate(d2.FromCion)
		if t2 != 0 {
			if t > 0 {
				if t < d2.CurTimes {
					d2.CurTimes = t
				}
			} else {
				d2.CurTimes = 0
			}
		}
		ret.Data = append(ret.Data, d2)
	}
	ret.Total = l.WithdrawTotalGet()
	return ret, nil
}
func (l *TypeModel) WithdrawTotalGet() int32 {
	ret, err := re.GetTokenRedis(l.ctx, l.svcCtx.Config.RedisConfig, rpc.RedisKey_name[int32(rpc.RedisKey_WithdrawTotal)])
	if err == nil {
		return cast.ToInt32(ret)
	}
	return 0
}
func (l *TypeModel) WithdrawOpen(ChannelType int32) error {
	if l.tx == nil {
		l.tx = query.Use(l.getDb())
	}
	h2 := l.tx.WithdrawType
	d2, err2 := h2.Where(h2.Type.Eq(ChannelType)).First()
	if err2 != nil {
		return err2
	}

	cur := time.Now()
	start := now.With(cur).BeginningOfDay()

	s := strings.Split(d2.WithdrawTime, "-")
	if len(s) != 2 {
		return xerrors.ErrUserWithdrawTimeCanNot
	}
	s0 := strings.Split(s[0], ":")
	if len(s0) != 3 {
		return xerrors.ErrUserWithdrawTimeCanNot
	}
	s1 := strings.Split(s[1], ":")
	if len(s1) != 3 {
		return xerrors.ErrUserWithdrawTimeCanNot
	}

	min := start.Add(
		time.Hour*time.Duration(cast.ToInt64(s0[0])) +
			time.Minute*time.Duration(cast.ToInt64(s0[1])) +
			time.Second*time.Duration(cast.ToInt64(s0[2])))
	max := start.Add(time.Hour*time.Duration(cast.ToInt64(s1[0])) +
		time.Minute*time.Duration(cast.ToInt64(s1[1])) +
		time.Second*time.Duration(cast.ToInt64(s1[2])))
	if cur.After(min) && cur.Before(max) {
	} else {
		return xerrors.ErrUserWithdrawTimeCanNot
	}
	err := l.WithdrawDailyTimesDel(ChannelType)
	return err
}
func (l *TypeModel) WithdrawDailyTimesDel(ChannelType int32) (err error) {
	t := l.WithdrawTotalGet()
	if t != 0 && t <= l.WithdrawTotalCurGet() {
		return xerrors.ErrUserWithdrawDailyTimesCanNot
	}
	// ----------------提现次数控制-----------------------
	g := l.tx.WithdrawType
	h := g.Where(g.Type.Eq(ChannelType))
	_, err = h.Where(g.CurTimes.Gt(0)).Update(g.CurTimes, g.CurTimes.Add(-1))
	return err
}
func (l *TypeModel) WithdrawDailyTimesPre() (err error) {
	if l.tx == nil {
		l.tx = query.Use(l.getDb())
	}
	g := l.tx.WithdrawType
	h := g.Where()
	d, err2 := h.Find()
	if err2 != nil {
		return err2
	}
	start := now.With(time.Now()).BeginningOfDay().Unix()
	for i, _ := range d {
		if start != d[i].BeginningOfDay {
			_, err = g.Where(g.Type.Eq(d[i].Type)).
				Where(g.BeginningOfDay.Neq(start)).
				UpdateSimple(g.CurTimes.SetCol(g.DailyTimes), g.BeginningOfDay.Value(start))
		}
	}

	return err
}
func (l *TypeModel) WithdrawDailyTimesAdd(ChannelType int32) error {
	if l.tx == nil {
		l.tx = query.Use(l.getDb())
	}
	h2 := l.tx.WithdrawType
	_, err2 := h2.Where(h2.Type.Eq(ChannelType)).
		Where(h2.CurTimes.LtCol(h2.DailyTimes)).
		Update(h2.CurTimes, h2.CurTimes.Add(1))
	if err2 != nil {
		return err2
	}
	return nil
}
func (l *TypeModel) WithdrawTotalCurGet() (ret int32) {
	if l.tx == nil {
		l.tx = query.Use(l.getDb())
	}
	d, err2 := l.tx.WithdrawType.Find()
	if err2 == nil {
		for i, _ := range d {
			ret += d[i].DailyTimes - d[i].CurTimes
		}
		return
	}
	return
}
